<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>核心源码模块 | Lampow燃的博客</title>
    <meta name="generator" content="VuePress 1.9.9">
    <link rel="icon" href="/blog/assets/img/vincentRan.ico">
    <link rel="manifest" href="/blog/manifest.json">
    <script src="/blog/scripts/global.js"></script>
    <script src="/blog/assets/js/autopush-baidu.js"></script>
    <script src="/blog/assets/js/autopush-360.js"></script>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui">
    <meta name="baidu-site-verification" content="gZcjfbZtAw">
    <meta name="google-site-verification" content="cEMNM1qDYFHDq8a4c2uT9n_3yX6kCJ4KolTcLk9DhV4">
    <meta name="360-site-verification" content="8b6f7e9dff6da70522ce0d5ae8ffd923">
    <meta name="author" content="Lampow燃">
    <meta name="keywords" content="vincentRan;Lampow燃;js;Javascript基础;前端;博客">
    <meta name="theme-color" content="#3eaf7c">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="msapplication-TileColor" content="#000000">
    
    <link rel="preload" href="/blog/assets/css/0.styles.b6bf8ae6.css" as="style"><link rel="preload" href="/blog/assets/js/app.7b4540b9.js" as="script"><link rel="preload" href="/blog/assets/js/2.b0da3abb.js" as="script"><link rel="preload" href="/blog/assets/js/90.9963ca39.js" as="script"><link rel="prefetch" href="/blog/assets/js/10.fad52a34.js"><link rel="prefetch" href="/blog/assets/js/11.d9c57454.js"><link rel="prefetch" href="/blog/assets/js/12.67814a82.js"><link rel="prefetch" href="/blog/assets/js/13.dff6097c.js"><link rel="prefetch" href="/blog/assets/js/14.63aca277.js"><link rel="prefetch" href="/blog/assets/js/15.2996c9e2.js"><link rel="prefetch" href="/blog/assets/js/16.97a52145.js"><link rel="prefetch" href="/blog/assets/js/17.cd17994a.js"><link rel="prefetch" href="/blog/assets/js/18.ac420f2a.js"><link rel="prefetch" href="/blog/assets/js/19.eb6b91bf.js"><link rel="prefetch" href="/blog/assets/js/20.cb363eca.js"><link rel="prefetch" href="/blog/assets/js/21.a4e99c33.js"><link rel="prefetch" href="/blog/assets/js/22.694a6ec1.js"><link rel="prefetch" href="/blog/assets/js/23.55cb3c0d.js"><link rel="prefetch" href="/blog/assets/js/24.0f31eaf1.js"><link rel="prefetch" href="/blog/assets/js/25.2eefb2bd.js"><link rel="prefetch" href="/blog/assets/js/26.9375d9cc.js"><link rel="prefetch" href="/blog/assets/js/27.15116a38.js"><link rel="prefetch" href="/blog/assets/js/28.19eef588.js"><link rel="prefetch" href="/blog/assets/js/29.49bf907e.js"><link rel="prefetch" href="/blog/assets/js/3.d02dbad1.js"><link rel="prefetch" href="/blog/assets/js/30.a3b1e05f.js"><link rel="prefetch" href="/blog/assets/js/31.e816c5a5.js"><link rel="prefetch" href="/blog/assets/js/32.0de6aa66.js"><link rel="prefetch" href="/blog/assets/js/33.0d6966b1.js"><link rel="prefetch" href="/blog/assets/js/34.9b7e8e14.js"><link rel="prefetch" href="/blog/assets/js/35.df38e2a9.js"><link rel="prefetch" href="/blog/assets/js/36.3f437700.js"><link rel="prefetch" href="/blog/assets/js/37.2c1de8b3.js"><link rel="prefetch" href="/blog/assets/js/38.86e11044.js"><link rel="prefetch" href="/blog/assets/js/39.82741cfc.js"><link rel="prefetch" href="/blog/assets/js/4.e142f4c4.js"><link rel="prefetch" href="/blog/assets/js/40.1e6de0bd.js"><link rel="prefetch" href="/blog/assets/js/41.5b9a2f33.js"><link rel="prefetch" href="/blog/assets/js/42.dbe88c0f.js"><link rel="prefetch" href="/blog/assets/js/43.48e12a76.js"><link rel="prefetch" href="/blog/assets/js/44.c5a6663b.js"><link rel="prefetch" href="/blog/assets/js/45.38f327a2.js"><link rel="prefetch" href="/blog/assets/js/46.527a0e03.js"><link rel="prefetch" href="/blog/assets/js/47.b8baaa72.js"><link rel="prefetch" href="/blog/assets/js/48.3447a56d.js"><link rel="prefetch" href="/blog/assets/js/49.cd301a0f.js"><link rel="prefetch" href="/blog/assets/js/5.d43d130b.js"><link rel="prefetch" href="/blog/assets/js/50.644742a2.js"><link rel="prefetch" href="/blog/assets/js/51.ae6a8437.js"><link rel="prefetch" href="/blog/assets/js/52.dfcb8f83.js"><link rel="prefetch" href="/blog/assets/js/53.2a0715a8.js"><link rel="prefetch" href="/blog/assets/js/54.fe7d4a37.js"><link rel="prefetch" href="/blog/assets/js/55.457aa0d9.js"><link rel="prefetch" href="/blog/assets/js/56.dc026f76.js"><link rel="prefetch" href="/blog/assets/js/57.dfa47cb4.js"><link rel="prefetch" href="/blog/assets/js/58.8dfdbcbb.js"><link rel="prefetch" href="/blog/assets/js/59.67f5108d.js"><link rel="prefetch" href="/blog/assets/js/6.e0517a23.js"><link rel="prefetch" href="/blog/assets/js/60.73f12c35.js"><link rel="prefetch" href="/blog/assets/js/61.a6281041.js"><link rel="prefetch" href="/blog/assets/js/62.a1672f34.js"><link rel="prefetch" href="/blog/assets/js/63.65b641c6.js"><link rel="prefetch" href="/blog/assets/js/64.01018dd4.js"><link rel="prefetch" href="/blog/assets/js/65.e7ffb165.js"><link rel="prefetch" href="/blog/assets/js/66.173f5f61.js"><link rel="prefetch" href="/blog/assets/js/67.5f7af08d.js"><link rel="prefetch" href="/blog/assets/js/68.d87b9899.js"><link rel="prefetch" href="/blog/assets/js/69.18f0835e.js"><link rel="prefetch" href="/blog/assets/js/7.da19f9b0.js"><link rel="prefetch" href="/blog/assets/js/70.9090fddd.js"><link rel="prefetch" href="/blog/assets/js/71.dd4e6e2c.js"><link rel="prefetch" href="/blog/assets/js/72.c42d4bf3.js"><link rel="prefetch" href="/blog/assets/js/73.5c5defd2.js"><link rel="prefetch" href="/blog/assets/js/74.b12fdeee.js"><link rel="prefetch" href="/blog/assets/js/75.7f085fdb.js"><link rel="prefetch" href="/blog/assets/js/76.f2d01ffb.js"><link rel="prefetch" href="/blog/assets/js/77.23a7ce10.js"><link rel="prefetch" href="/blog/assets/js/78.3b39d101.js"><link rel="prefetch" href="/blog/assets/js/79.42d64efd.js"><link rel="prefetch" href="/blog/assets/js/8.00fa029c.js"><link rel="prefetch" href="/blog/assets/js/80.64996c95.js"><link rel="prefetch" href="/blog/assets/js/81.a15f0118.js"><link rel="prefetch" href="/blog/assets/js/82.726c1156.js"><link rel="prefetch" href="/blog/assets/js/83.8b3a794d.js"><link rel="prefetch" href="/blog/assets/js/84.7cbe7d64.js"><link rel="prefetch" href="/blog/assets/js/85.3ec16acd.js"><link rel="prefetch" href="/blog/assets/js/86.41b3d3af.js"><link rel="prefetch" href="/blog/assets/js/87.c6e2a7c9.js"><link rel="prefetch" href="/blog/assets/js/88.4d4b145b.js"><link rel="prefetch" href="/blog/assets/js/89.04660517.js"><link rel="prefetch" href="/blog/assets/js/9.12b493d7.js"><link rel="prefetch" href="/blog/assets/js/91.50f67c60.js"><link rel="prefetch" href="/blog/assets/js/92.f109d0d0.js"><link rel="prefetch" href="/blog/assets/js/93.5664c7c2.js"><link rel="prefetch" href="/blog/assets/js/94.889bd5e0.js"><link rel="prefetch" href="/blog/assets/js/95.cfcb0fb3.js">
    <link rel="stylesheet" href="/blog/assets/css/0.styles.b6bf8ae6.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/blog/" class="home-link router-link-active"><img src="/blog/assets/img/vincentRan.jpg" alt="Lampow燃的博客" class="logo"> <span class="site-name can-hide">Lampow燃的博客</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="工作台" class="dropdown-title"><span class="title">工作台</span> <span class="arrow down"></span></button> <button type="button" aria-label="工作台" class="mobile-dropdown-title"><span class="title">工作台</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/article/工作台/工作台.html" class="nav-link">
  工作台
</a></li><li class="dropdown-item"><h4>
          未来探索
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/未来探索/营销公司.html" class="nav-link">
  营销
</a></li><li class="dropdown-subitem"><a href="/blog/article/未来探索/野外单兵防护.html" class="nav-link">
  野外单兵防护
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="计算机原理" class="dropdown-title"><span class="title">计算机原理</span> <span class="arrow down"></span></button> <button type="button" aria-label="计算机原理" class="mobile-dropdown-title"><span class="title">计算机原理</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/article/计算机原理/CPU结构以及简单运行原理.html" class="nav-link">
  CPU结构以及简单运行原理
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/计算机原理/进程和线程.html" class="nav-link">
  进程和线程
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Javascript 基础" class="dropdown-title"><span class="title">Javascript 基础</span> <span class="arrow down"></span></button> <button type="button" aria-label="Javascript 基础" class="mobile-dropdown-title"><span class="title">Javascript 基础</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/article/js-basic/数据类型.html" class="nav-link">
  数据类型
</a></li><li class="dropdown-item"><h4>
          关键字
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-basic/关键字/通用关键字.html" class="nav-link">
  通用关键字
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/关键字/async &amp; await.html" class="nav-link">
  async &amp; await
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/关键字/new.html" class="nav-link">
  new
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/关键字/yield.html" class="nav-link">
  yield
</a></li></ul></li><li class="dropdown-item"><h4>
          常用内置对象
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Object.html" class="nav-link">
  Object
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Function.html" class="nav-link">
  Function
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/GeneratorFunction.html" class="nav-link">
  GeneratorFunction
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Promise.html" class="nav-link">
  Promise
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Reflect.html" class="nav-link">
  Reflect
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Array.html" class="nav-link">
  Array
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Set.html" class="nav-link">
  Set
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Proxy.html" class="nav-link">
  Proxy
</a></li></ul></li><li class="dropdown-item"><h4>
          构造函数-原型-原型链
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-basic/构造函数-原型-原型链/构造函数.html" class="nav-link">
  构造函数
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/构造函数-原型-原型链/原型.html" class="nav-link">
  原型
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/构造函数-原型-原型链/原型链.html" class="nav-link">
  原型链
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/构造函数-原型-原型链/箭头函数.html" class="nav-link">
  箭头函数
</a></li></ul></li><li class="dropdown-item"><!----> <a href="/blog/article/js-basic/1-4、数组操作.html" class="nav-link">
  数组操作
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/js-basic/深浅拷贝.html" class="nav-link">
  引用类型之深拷贝浅拷贝
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/js-basic/1-6、知识体系.html" class="nav-link">
  知识体系
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Javascript 进阶" class="dropdown-title"><span class="title">Javascript 进阶</span> <span class="arrow down"></span></button> <button type="button" aria-label="Javascript 进阶" class="mobile-dropdown-title"><span class="title">Javascript 进阶</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/article/js-upgrade/模块化/模块化.html" class="nav-link">
  模块化
</a></li><li class="dropdown-item"><h4>
          性能优化
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/性能优化/避免内存泄漏.html" class="nav-link">
  避免内存泄漏
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/性能优化/v8垃圾回收机制.html" class="nav-link">
  v8垃圾回收机制
</a></li></ul></li><li class="dropdown-item"><h4>
          编程范式
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/编程范式/编程范式.html" class="nav-link">
  编程范式
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/编程范式/面向对象_封装.html" class="nav-link">
  面向对象编程
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/编程范式/函数式编程.html" class="nav-link">
  函数式编程
</a></li></ul></li><li class="dropdown-item"><h4>
          编程原则
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/编程原则/编程原则.html" class="nav-link">
  编程原则
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/编程原则/Immutable原则.html" class="nav-link">
  Immutable原则
</a></li></ul></li><li class="dropdown-item"><h4>
          设计模式
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/设计模式/什么是设计模式.html" class="nav-link">
  什么是设计模式
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/设计模式/访问者模式.html" class="nav-link">
  访问者模式
</a></li></ul></li><li class="dropdown-item"><h4>
          常见算法
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/算法/贪心算法.html" class="nav-link">
  贪心算法
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/算法/LRU（least recently used）.html" class="nav-link">
  LRU（least recently used）
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="框架" class="dropdown-title"><span class="title">框架</span> <span class="arrow down"></span></button> <button type="button" aria-label="框架" class="mobile-dropdown-title"><span class="title">框架</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          NestJS
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/框架/NestJS/初始NestJS.html" class="nav-link">
  初始NestJS
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/NestJS/数据库.html" class="nav-link">
  数据库
</a></li></ul></li><li class="dropdown-item"><h4>
          typescript
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/框架/typescript/初识TypeScript.html" class="nav-link">
  初识TypeScript
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/typescript/基本类型.html" class="nav-link">
  基本类型
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/typescript/进阶类型.html" class="nav-link">
  进阶类型
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/typescript/最佳实践.html" class="nav-link">
  最佳实践
</a></li></ul></li><li class="dropdown-item"><h4>
          React
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/框架/react/基础用法.html" class="nav-link">
  基础用法
</a></li></ul></li><li class="dropdown-item"><h4>
          Vue
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/框架/vue/生命周期&amp;执行过程.html" class="nav-link">
  生命周期&amp;执行过程
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/vue/组件间通信.html" class="nav-link">
  组件间通信
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/vue/自定义指令.html" class="nav-link">
  自定义指令
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/vue/手撸ViewModel.html" class="nav-link">
  手撸ViewModel
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/vue/源码解析/核心源码模块.html" class="nav-link">
  源码解析
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端工程化" class="dropdown-title"><span class="title">前端工程化</span> <span class="arrow down"></span></button> <button type="button" aria-label="前端工程化" class="mobile-dropdown-title"><span class="title">前端工程化</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          持续集成与交付
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/前端工程化/CI&amp;CD/CI&amp;CD.html" class="nav-link">
  持续集成与交付
</a></li><li class="dropdown-subitem"><a href="/blog/article/前端工程化/CI&amp;CD/编译打包/编译原理.html" class="nav-link">
  编译打包
</a></li><li class="dropdown-subitem"><a href="/blog/article/前端工程化/CI&amp;CD/自动化测试/自动化测试.html" class="nav-link">
  自动化测试
</a></li></ul></li><li class="dropdown-item"><h4>
          脚手架开发
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/前端工程化/脚手架开发/npm原生/npm脚手架开发.html" class="nav-link">
  npm原生
</a></li><li class="dropdown-subitem"><a href="/blog/article/前端工程化/脚手架开发/lerna库/快速上手.html" class="nav-link">
  lerna库
</a></li><li class="dropdown-subitem"><a href="/blog/article/前端工程化/脚手架开发/commander/commander.html" class="nav-link">
  commander管理命令
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="工具代码" class="dropdown-title"><span class="title">工具代码</span> <span class="arrow down"></span></button> <button type="button" aria-label="工具代码" class="mobile-dropdown-title"><span class="title">工具代码</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/article/工具代码/正则.html" class="nav-link">
  正则
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/工具代码/浏览器扩展.html" class="nav-link">
  浏览器扩展
</a></li><li class="dropdown-item"><h4>
          轮子系列
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/订阅发布模式.html" class="nav-link">
  订阅发布模式
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/深拷贝.html" class="nav-link">
  深拷贝
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/Promise.html" class="nav-link">
  22行简洁的Promise
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/健壮的Promise.html" class="nav-link">
  健壮的Promise
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/节流and防抖.html" class="nav-link">
  节流and防抖
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/链表.html" class="nav-link">
  链表
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/Immer核心.html" class="nav-link">
  Immer核心
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/手写new.html" class="nav-link">
  手写new
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="web3D" class="dropdown-title"><span class="title">web3D</span> <span class="arrow down"></span></button> <button type="button" aria-label="web3D" class="mobile-dropdown-title"><span class="title">web3D</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/article/web3D/webgl/plan.html" class="nav-link">
  学习计划
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/web3D/webgl/WebGL2_Attr.html" class="nav-link">
  WebGL2 属性
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/web3D/webgl/WebGL2_API.html" class="nav-link">
  WebGL2 API
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/web3D/webgl/WebGL2_Interface.html" class="nav-link">
  WebGL2 接口
</a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="工作台" class="dropdown-title"><span class="title">工作台</span> <span class="arrow down"></span></button> <button type="button" aria-label="工作台" class="mobile-dropdown-title"><span class="title">工作台</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/article/工作台/工作台.html" class="nav-link">
  工作台
</a></li><li class="dropdown-item"><h4>
          未来探索
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/未来探索/营销公司.html" class="nav-link">
  营销
</a></li><li class="dropdown-subitem"><a href="/blog/article/未来探索/野外单兵防护.html" class="nav-link">
  野外单兵防护
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="计算机原理" class="dropdown-title"><span class="title">计算机原理</span> <span class="arrow down"></span></button> <button type="button" aria-label="计算机原理" class="mobile-dropdown-title"><span class="title">计算机原理</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/article/计算机原理/CPU结构以及简单运行原理.html" class="nav-link">
  CPU结构以及简单运行原理
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/计算机原理/进程和线程.html" class="nav-link">
  进程和线程
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Javascript 基础" class="dropdown-title"><span class="title">Javascript 基础</span> <span class="arrow down"></span></button> <button type="button" aria-label="Javascript 基础" class="mobile-dropdown-title"><span class="title">Javascript 基础</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/article/js-basic/数据类型.html" class="nav-link">
  数据类型
</a></li><li class="dropdown-item"><h4>
          关键字
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-basic/关键字/通用关键字.html" class="nav-link">
  通用关键字
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/关键字/async &amp; await.html" class="nav-link">
  async &amp; await
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/关键字/new.html" class="nav-link">
  new
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/关键字/yield.html" class="nav-link">
  yield
</a></li></ul></li><li class="dropdown-item"><h4>
          常用内置对象
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Object.html" class="nav-link">
  Object
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Function.html" class="nav-link">
  Function
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/GeneratorFunction.html" class="nav-link">
  GeneratorFunction
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Promise.html" class="nav-link">
  Promise
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Reflect.html" class="nav-link">
  Reflect
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Array.html" class="nav-link">
  Array
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Set.html" class="nav-link">
  Set
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/内置对象/Proxy.html" class="nav-link">
  Proxy
</a></li></ul></li><li class="dropdown-item"><h4>
          构造函数-原型-原型链
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-basic/构造函数-原型-原型链/构造函数.html" class="nav-link">
  构造函数
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/构造函数-原型-原型链/原型.html" class="nav-link">
  原型
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/构造函数-原型-原型链/原型链.html" class="nav-link">
  原型链
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-basic/构造函数-原型-原型链/箭头函数.html" class="nav-link">
  箭头函数
</a></li></ul></li><li class="dropdown-item"><!----> <a href="/blog/article/js-basic/1-4、数组操作.html" class="nav-link">
  数组操作
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/js-basic/深浅拷贝.html" class="nav-link">
  引用类型之深拷贝浅拷贝
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/js-basic/1-6、知识体系.html" class="nav-link">
  知识体系
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Javascript 进阶" class="dropdown-title"><span class="title">Javascript 进阶</span> <span class="arrow down"></span></button> <button type="button" aria-label="Javascript 进阶" class="mobile-dropdown-title"><span class="title">Javascript 进阶</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/article/js-upgrade/模块化/模块化.html" class="nav-link">
  模块化
</a></li><li class="dropdown-item"><h4>
          性能优化
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/性能优化/避免内存泄漏.html" class="nav-link">
  避免内存泄漏
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/性能优化/v8垃圾回收机制.html" class="nav-link">
  v8垃圾回收机制
</a></li></ul></li><li class="dropdown-item"><h4>
          编程范式
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/编程范式/编程范式.html" class="nav-link">
  编程范式
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/编程范式/面向对象_封装.html" class="nav-link">
  面向对象编程
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/编程范式/函数式编程.html" class="nav-link">
  函数式编程
</a></li></ul></li><li class="dropdown-item"><h4>
          编程原则
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/编程原则/编程原则.html" class="nav-link">
  编程原则
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/编程原则/Immutable原则.html" class="nav-link">
  Immutable原则
</a></li></ul></li><li class="dropdown-item"><h4>
          设计模式
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/设计模式/什么是设计模式.html" class="nav-link">
  什么是设计模式
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/设计模式/访问者模式.html" class="nav-link">
  访问者模式
</a></li></ul></li><li class="dropdown-item"><h4>
          常见算法
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/算法/贪心算法.html" class="nav-link">
  贪心算法
</a></li><li class="dropdown-subitem"><a href="/blog/article/js-upgrade/算法/LRU（least recently used）.html" class="nav-link">
  LRU（least recently used）
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="框架" class="dropdown-title"><span class="title">框架</span> <span class="arrow down"></span></button> <button type="button" aria-label="框架" class="mobile-dropdown-title"><span class="title">框架</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          NestJS
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/框架/NestJS/初始NestJS.html" class="nav-link">
  初始NestJS
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/NestJS/数据库.html" class="nav-link">
  数据库
</a></li></ul></li><li class="dropdown-item"><h4>
          typescript
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/框架/typescript/初识TypeScript.html" class="nav-link">
  初识TypeScript
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/typescript/基本类型.html" class="nav-link">
  基本类型
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/typescript/进阶类型.html" class="nav-link">
  进阶类型
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/typescript/最佳实践.html" class="nav-link">
  最佳实践
</a></li></ul></li><li class="dropdown-item"><h4>
          React
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/框架/react/基础用法.html" class="nav-link">
  基础用法
</a></li></ul></li><li class="dropdown-item"><h4>
          Vue
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/框架/vue/生命周期&amp;执行过程.html" class="nav-link">
  生命周期&amp;执行过程
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/vue/组件间通信.html" class="nav-link">
  组件间通信
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/vue/自定义指令.html" class="nav-link">
  自定义指令
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/vue/手撸ViewModel.html" class="nav-link">
  手撸ViewModel
</a></li><li class="dropdown-subitem"><a href="/blog/article/框架/vue/源码解析/核心源码模块.html" class="nav-link">
  源码解析
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端工程化" class="dropdown-title"><span class="title">前端工程化</span> <span class="arrow down"></span></button> <button type="button" aria-label="前端工程化" class="mobile-dropdown-title"><span class="title">前端工程化</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          持续集成与交付
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/前端工程化/CI&amp;CD/CI&amp;CD.html" class="nav-link">
  持续集成与交付
</a></li><li class="dropdown-subitem"><a href="/blog/article/前端工程化/CI&amp;CD/编译打包/编译原理.html" class="nav-link">
  编译打包
</a></li><li class="dropdown-subitem"><a href="/blog/article/前端工程化/CI&amp;CD/自动化测试/自动化测试.html" class="nav-link">
  自动化测试
</a></li></ul></li><li class="dropdown-item"><h4>
          脚手架开发
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/前端工程化/脚手架开发/npm原生/npm脚手架开发.html" class="nav-link">
  npm原生
</a></li><li class="dropdown-subitem"><a href="/blog/article/前端工程化/脚手架开发/lerna库/快速上手.html" class="nav-link">
  lerna库
</a></li><li class="dropdown-subitem"><a href="/blog/article/前端工程化/脚手架开发/commander/commander.html" class="nav-link">
  commander管理命令
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="工具代码" class="dropdown-title"><span class="title">工具代码</span> <span class="arrow down"></span></button> <button type="button" aria-label="工具代码" class="mobile-dropdown-title"><span class="title">工具代码</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/article/工具代码/正则.html" class="nav-link">
  正则
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/工具代码/浏览器扩展.html" class="nav-link">
  浏览器扩展
</a></li><li class="dropdown-item"><h4>
          轮子系列
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/订阅发布模式.html" class="nav-link">
  订阅发布模式
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/深拷贝.html" class="nav-link">
  深拷贝
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/Promise.html" class="nav-link">
  22行简洁的Promise
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/健壮的Promise.html" class="nav-link">
  健壮的Promise
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/节流and防抖.html" class="nav-link">
  节流and防抖
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/链表.html" class="nav-link">
  链表
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/Immer核心.html" class="nav-link">
  Immer核心
</a></li><li class="dropdown-subitem"><a href="/blog/article/工具代码/轮子系列/手写new.html" class="nav-link">
  手写new
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="web3D" class="dropdown-title"><span class="title">web3D</span> <span class="arrow down"></span></button> <button type="button" aria-label="web3D" class="mobile-dropdown-title"><span class="title">web3D</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/article/web3D/webgl/plan.html" class="nav-link">
  学习计划
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/web3D/webgl/WebGL2_Attr.html" class="nav-link">
  WebGL2 属性
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/web3D/webgl/WebGL2_API.html" class="nav-link">
  WebGL2 API
</a></li><li class="dropdown-item"><!----> <a href="/blog/article/web3D/webgl/WebGL2_Interface.html" class="nav-link">
  WebGL2 接口
</a></li></ul></div></div> <!----></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>工作台</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>计算机原理</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Javascript 基础</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Javascript 进阶</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>框架</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><section class="sidebar-group collapsable is-sub-group depth-1"><a href="/blog/article/框架/NestJS/初始NestJS" class="sidebar-heading clickable"><span>NestJS</span> <span class="arrow right"></span></a> <!----></section></li><li><section class="sidebar-group collapsable is-sub-group depth-1"><a href="/blog/article/框架/typescript/初识TypeScript" class="sidebar-heading clickable"><span>typescript</span> <span class="arrow right"></span></a> <!----></section></li><li><section class="sidebar-group collapsable is-sub-group depth-1"><a href="/blog/article/框架/react/基础用法" class="sidebar-heading clickable"><span>React</span> <span class="arrow right"></span></a> <!----></section></li><li><section class="sidebar-group collapsable is-sub-group depth-1"><a href="/blog/article/框架/vue/生命周期&amp;执行过程" class="sidebar-heading clickable open"><span>Vue</span> <span class="arrow down"></span></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/blog/article/框架/vue/生命周期&amp;执行过程.html" class="sidebar-link">生命周期&amp;执行过程</a></li><li><a href="/blog/article/框架/vue/组件间通信.html" class="sidebar-link">组件间通信</a></li><li><a href="/blog/article/框架/vue/自定义指令.html" class="sidebar-link">自定义指令</a></li><li><a href="/blog/article/框架/vue/手撸ViewModel.html" class="sidebar-link">手撸ViewModel</a></li><li><section class="sidebar-group collapsable is-sub-group depth-2"><a href="/blog/article/框架/vue/源码解析/核心源码模块" class="sidebar-heading clickable open active"><span>源码解析</span> <span class="arrow down"></span></a> <ul class="sidebar-links sidebar-group-items"><li><a href="/blog/article/框架/vue/源码解析/核心源码模块.html" class="active sidebar-link">核心源码模块</a></li></ul></section></li></ul></section></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>前端工程化</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>工具代码</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>web3D</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h2 id="核心源码模块"><a href="#核心源码模块" class="header-anchor">#</a> 核心源码模块</h2> <h3 id="前置知识"><a href="#前置知识" class="header-anchor">#</a> 前置知识</h3> <div class="custom-block tip"><p class="custom-block-title">flow 做类型检查</p> <h4 id="历史问题-当时-ts-还不够流行"><a href="#历史问题-当时-ts-还不够流行" class="header-anchor">#</a> 历史问题，当时 ts 还不够流行</h4> <h4 id="flow-用处"><a href="#flow-用处" class="header-anchor">#</a> flow 用处</h4> <ol><li>类型推断</li> <li>类型注释</li></ol> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/** @flow */</span> 标注这个文件需要flow去解析类型
</code></pre></div></div> <h3 id="源码入口分析"><a href="#源码入口分析" class="header-anchor">#</a> 源码入口分析</h3> <div class="custom-block warning"><p class="custom-block-title">源码阅读的方法</p> <ol><li>先找 pkg.json 文件</li> <li>寻找 build 入口</li> <li>找到打包文件，vue2 默认打包模器是 rollup，build 只是产出 rollup 的打包配置</li> <li>在 config 文件里记录了 builds 打包列表，config 里也记录了 aliases 配置，标识了打包配置的入口路径 entry 里的 web，代表 src/platforms/web 目录</li> <li>找到 runtime+compile 打包配置项，找到入口文件是 src/platforms/web/entry-runtime-with-compiler.js</li> <li>再追寻 vue 创建的起点，找到真正的起始文件入口是 src\core\instance\index.js</li></ol> <h4 id="所有-npm-包源码阅读-都可以按照这种模式-pkg-json-build-入口-分析打包程序-找到编译入口"><a href="#所有-npm-包源码阅读-都可以按照这种模式-pkg-json-build-入口-分析打包程序-找到编译入口" class="header-anchor">#</a> 所有 npm 包源码阅读，都可以按照这种模式：pkg.json -&gt; build 入口 -&gt; 分析打包程序 -&gt; 找到编译入口</h4></div> <h3 id="vue-执行核心过程"><a href="#vue-执行核心过程" class="header-anchor">#</a> Vue 执行核心过程</h3> <h4 id="new-vue-init-mount-compile-render-vnode-patch-vdom"><a href="#new-vue-init-mount-compile-render-vnode-patch-vdom" class="header-anchor">#</a> new Vue -&gt; init -&gt; $mount -&gt; compile -&gt; render -&gt; vnode -&gt; patch -&gt; vdom</h4> <h3 id="源码分析-起始入口"><a href="#源码分析-起始入口" class="header-anchor">#</a> 源码分析 起始入口</h3> <div class="custom-block warning"><p class="custom-block-title">src\core\instance\index.js</p> <div class="language-js extra-class"><div class="highlight-lines"><br><br><br><br><br><br><br><br><div class="highlighted"> </div><br><br><br><br><br><br><br><br><br><br><br><br><br><br></div><pre class="language-js"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> initMixin <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./init'</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> stateMixin <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./state'</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> renderMixin <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./render'</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> eventsMixin <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./events'</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> lifecycleMixin <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./lifecycle'</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> warn <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../util/index'</span>

<span class="token keyword">function</span> <span class="token function">Vue</span><span class="token punctuation">(</span><span class="token parameter">options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 后续所有源码遇到类似的环境判断都可以忽略</span>
  <span class="token comment">// if (process.env.NODE_ENV !== 'production' &amp;&amp; !(this instanceof Vue)) {</span>
  <span class="token comment">//   warn('Vue is a constructor and should be called with the `new` keyword')</span>
  <span class="token comment">// }</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_init</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token function">initMixin</span><span class="token punctuation">(</span>Vue<span class="token punctuation">)</span> <span class="token comment">// 初始化 vue 的生命周期</span>
<span class="token function">stateMixin</span><span class="token punctuation">(</span>Vue<span class="token punctuation">)</span>
<span class="token function">eventsMixin</span><span class="token punctuation">(</span>Vue<span class="token punctuation">)</span>
<span class="token function">lifecycleMixin</span><span class="token punctuation">(</span>Vue<span class="token punctuation">)</span>
<span class="token function">renderMixin</span><span class="token punctuation">(</span>Vue<span class="token punctuation">)</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> Vue
</code></pre></div><h4 id="为什么-vue-不用类去做-而用构造函数去实现"><a href="#为什么-vue-不用类去做-而用构造函数去实现" class="header-anchor">#</a> 为什么 vue 不用类去做，而用构造函数去实现？</h4> <ol><li>vue 源码里有很多 AOP 编程的思想，如果通过 class 来创建，则会导致 construct 函数很难扩展</li> <li>vue 的很多属性和方法都是动态写入的，无法在一开始就把所有方法和属性定义出来</li></ol></div> <h3 id="源码分析-initmixin"><a href="#源码分析-initmixin" class="header-anchor">#</a> 源码分析 initMixin</h3> <div class="custom-block warning"><p class="custom-block-title">src\core\instance\init.js</p> <p>这是<code>生命周期</code>钩子<code>起始</code>的地方</p> <div class="language-js extra-class"><div class="highlight-lines"><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><div class="highlighted"> </div><br><div class="highlighted"> </div><br><div class="highlighted"> </div><br><br><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><div class="highlighted"> </div><br><br><br><br></div><pre class="language-js"><code><span class="token keyword">let</span> uid <span class="token operator">=</span> <span class="token number">0</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">initMixin</span><span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">Vue</span><span class="token operator">:</span> Class<span class="token operator">&lt;</span>Component<span class="token operator">&gt;</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token class-name">Vue</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">_init</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">options<span class="token operator">?</span><span class="token operator">:</span> Object</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token literal-property property">vm</span><span class="token operator">:</span> Component <span class="token operator">=</span> <span class="token keyword">this</span>
    vm<span class="token punctuation">.</span>_uid <span class="token operator">=</span> uid<span class="token operator">++</span>
    vm<span class="token punctuation">.</span>_isVue <span class="token operator">=</span> <span class="token boolean">true</span>
    <span class="token comment">// merge options</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>options <span class="token operator">&amp;&amp;</span> options<span class="token punctuation">.</span>_isComponent<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">initInternalComponent</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> options<span class="token punctuation">)</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      vm<span class="token punctuation">.</span>$options <span class="token operator">=</span> <span class="token function">mergeOptions</span><span class="token punctuation">(</span><span class="token function">resolveConstructorOptions</span><span class="token punctuation">(</span>vm<span class="token punctuation">.</span>constructor<span class="token punctuation">)</span><span class="token punctuation">,</span> options <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> vm<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>

    vm<span class="token punctuation">.</span>_renderProxy <span class="token operator">=</span> vm
    vm<span class="token punctuation">.</span>_self <span class="token operator">=</span> vm
    <span class="token function">initLifecycle</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span> <span class="token comment">// 初始化一些变量</span>
    <span class="token function">initEvents</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span> <span class="token comment">// 初始化组件的事件系统 @onClick=&quot;xxx&quot; $emit('xxx',{})</span>
    <span class="token function">initRender</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span> <span class="token comment">// 初始化插槽、$createElement、初始化$attrs、$listeners</span>
    <span class="token function">callHook</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> <span class="token string">'beforeCreate'</span><span class="token punctuation">)</span> <span class="token comment">// 执行 beforeCreate 钩子</span>
    <span class="token function">initInjections</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span> <span class="token comment">// resolve injections before data/props</span>
    <span class="token function">initState</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span> <span class="token comment">// 初始化 data/props</span>
    <span class="token function">initProvide</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span> <span class="token comment">// resolve provide after data/props</span>
    <span class="token function">callHook</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> <span class="token string">'created'</span><span class="token punctuation">)</span> <span class="token comment">// 执行 created 钩子</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>vm<span class="token punctuation">.</span>$options<span class="token punctuation">.</span>el<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      vm<span class="token punctuation">.</span><span class="token function">$mount</span><span class="token punctuation">(</span>vm<span class="token punctuation">.</span>$options<span class="token punctuation">.</span>el<span class="token punctuation">)</span>  <span class="token comment">// $mount 源码位置：src/platforms/web/runtime/index.js</span>
      <span class="token comment">// 核心就是 `mountComponent` 方法，源码位置：src/core/instance/lifecycle.js</span>
      <span class="token comment">// 解析模板字符串</span>
      <span class="token comment">// 绑定 $el</span>
      <span class="token comment">// 执行 beforeMount 钩子</span>
      <span class="token comment">// 创建观察者 Watcher</span>

      <span class="token comment">// _render 是生成 vdom 的过程 -&gt; VDOM</span>
      <span class="token comment">// _update -&gt; patch -&gt; DOM是生成真实DOM过程</span>
      <span class="token comment">// vm._update(vm._render(), hydrating); // 生成vdom，patch到真实dom</span>

      <span class="token comment">// 添加 beforeUpdate 钩子到 Watcher 列表，监听data变化，触发 beforeUpdate 钩子</span>
      <span class="token comment">// 执行 mounted 钩子</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div></div> <h3 id="生成-vdom-render"><a href="#生成-vdom-render" class="header-anchor">#</a> 生成 VDOM: <code>_render</code></h3> <div class="custom-block warning"><p class="custom-block-title">src/core/instance/render.js</p> <div class="language-js extra-class"><div class="highlight-lines"><br><br><br><br><br><br><br><br><br><br><br><br><br><div class="highlighted"> </div><div class="highlighted"> </div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><div class="highlighted"> </div><div class="highlighted"> </div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br></div><pre class="language-js"><code><span class="token class-name">Vue</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">_render</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> VNode <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token literal-property property">vm</span><span class="token operator">:</span> Component <span class="token operator">=</span> <span class="token keyword">this</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> _parentVnode <span class="token punctuation">}</span> <span class="token operator">=</span> vm<span class="token punctuation">.</span>$options

  <span class="token keyword">if</span> <span class="token punctuation">(</span>_parentVnode<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    vm<span class="token punctuation">.</span>$scopedSlots <span class="token operator">=</span> <span class="token function">normalizeScopedSlots</span><span class="token punctuation">(</span>_parentVnode<span class="token punctuation">.</span>data<span class="token punctuation">.</span>scopedSlots<span class="token punctuation">,</span> vm<span class="token punctuation">.</span>$slots<span class="token punctuation">,</span> vm<span class="token punctuation">.</span>$scopedSlots<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>

  vm<span class="token punctuation">.</span>$vnode <span class="token operator">=</span> _parentVnode
  <span class="token keyword">let</span> vnode
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    currentRenderingInstance <span class="token operator">=</span> vm
    <span class="token comment">/**
     * 用 render 创建组件。传统的 template 创建组件也会被编译成这种写法
     * 核心还是用 vm.$createElement -&gt; createElement -&gt; _createElement -&gt; `new VNode` 创建 VDOM
     * &lt;script&gt;
     *   export default {
     *     props: {
     *       name: {
     *         require: true,
     *       }
     *     },
     *     render(createElement) {
     *       let self = this
     *       return createElement('input', {
     *         domProps: {
     *           value: self.name
     *         },
     *         on: {
     *           input(event) {
     *             self.$emit('input', event.target.value)
     *           }
     *         }
     *       })
     *     }
     *   };
     * &lt;/script&gt;
     */</span>
    <span class="token comment">// 此处 render.call 就是 render 创建组件时，传入的配置项的 render函数</span>
    vnode <span class="token operator">=</span> <span class="token function">render</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>vm<span class="token punctuation">.</span>_renderProxy<span class="token punctuation">,</span> vm<span class="token punctuation">.</span>$createElement<span class="token punctuation">)</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">handleError</span><span class="token punctuation">(</span>e<span class="token punctuation">,</span> vm<span class="token punctuation">,</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">render</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
    vnode <span class="token operator">=</span> vm<span class="token punctuation">.</span>_vnode
  <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
    currentRenderingInstance <span class="token operator">=</span> <span class="token keyword">null</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// if the returned array contains only a single node, allow it</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>vnode<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> vnode<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    vnode <span class="token operator">=</span> vnode<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// return empty vnode in case the render function errored out</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token punctuation">(</span>vnode <span class="token keyword">instanceof</span> <span class="token class-name">VNode</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    vnode <span class="token operator">=</span> <span class="token function">createEmptyVNode</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// set parent</span>
  vnode<span class="token punctuation">.</span>parent <span class="token operator">=</span> _parentVnode
  <span class="token keyword">return</span> vnode
<span class="token punctuation">}</span>
</code></pre></div></div> <h3 id="diff-算法前奏-update-patch-patch"><a href="#diff-算法前奏-update-patch-patch" class="header-anchor">#</a> diff 算法前奏: <code>_update -&gt; __patch__ -&gt; patch</code></h3> <div class="custom-block warning"><p class="custom-block-title">src/core/vdom/patch.js</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">patch</span><span class="token punctuation">(</span><span class="token parameter">oldVnode<span class="token punctuation">,</span> vnode<span class="token punctuation">,</span> hydrating<span class="token punctuation">,</span> removeOnly</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 判断新的vnode是否为空</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isUndef</span><span class="token punctuation">(</span>vnode<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 如果老的vnode不为空 卸载所有的老vnode</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">invokeDestroyHook</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">)</span>
    <span class="token keyword">return</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">let</span> isInitialPatch <span class="token operator">=</span> <span class="token boolean">false</span>
  <span class="token comment">// 用来存储 insert钩子函数，在插入节点之前调用</span>
  <span class="token keyword">const</span> insertedVnodeQueue <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
  <span class="token comment">// 如果老节点不存在，直接创建新节点</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isUndef</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    isInitialPatch <span class="token operator">=</span> <span class="token boolean">true</span>
    <span class="token function">createElm</span><span class="token punctuation">(</span>vnode<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">)</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
    <span class="token comment">// 是不是元素节点</span>
    <span class="token keyword">const</span> isRealElement <span class="token operator">=</span> <span class="token function">isDef</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">.</span>nodeType<span class="token punctuation">)</span>
    <span class="token comment">// 当老节点不是真实的DOM节点，并且新老节点的type和key相同，进行patchVnode更新工作</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>isRealElement <span class="token operator">&amp;&amp;</span> <span class="token function">sameVnode</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">,</span> vnode<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">patchVnode</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">,</span> vnode<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> removeOnly<span class="token punctuation">)</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      <span class="token comment">// ... 此处省略是真实dom的一系列操作，我们只关系虚拟DOM的patch</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 执行 虚拟 dom 的 insert 钩子函数</span>
  <span class="token function">invokeInsertHook</span><span class="token punctuation">(</span>vnode<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">,</span> isInitialPatch<span class="token punctuation">)</span>
  <span class="token comment">// 返回最新 vnode 的 elm ，也就是真实的 dom节点</span>
  <span class="token keyword">return</span> vnode<span class="token punctuation">.</span>elm
<span class="token punctuation">}</span>
</code></pre></div></div> <h3 id="diff-算法核心-update-patch-patch-patchvnode"><a href="#diff-算法核心-update-patch-patch-patchvnode" class="header-anchor">#</a> diff 算法核心: <code>_update -&gt; __patch__ -&gt; patch -&gt; patchVnode</code></h3> <div class="custom-block warning"><p class="custom-block-title">src/core/vdom/patch.js</p> <div class="language-js extra-class"><div class="highlight-lines"><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><div class="highlighted"> </div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br></div><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">patchVnode</span><span class="token punctuation">(</span>
  oldVnode<span class="token punctuation">,</span> <span class="token comment">// 老的虚拟 DOM 节点</span>
  vnode<span class="token punctuation">,</span> <span class="token comment">// 新节点</span>
  insertedVnodeQueue<span class="token punctuation">,</span> <span class="token comment">// 插入节点队列</span>
  ownerArray<span class="token punctuation">,</span> <span class="token comment">// 节点数组</span>
  index<span class="token punctuation">,</span> <span class="token comment">// 当前节点的下标</span>
  removeOnly
<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 新老节点对比地址一样，说明没有变更过，是同一个对象，直接跳过</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>oldVnode <span class="token operator">===</span> vnode<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span>vnode<span class="token punctuation">.</span>elm<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">isDef</span><span class="token punctuation">(</span>ownerArray<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// clone reused vnode</span>
    vnode <span class="token operator">=</span> ownerArray<span class="token punctuation">[</span>index<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">cloneVNode</span><span class="token punctuation">(</span>vnode<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">const</span> elm <span class="token operator">=</span> <span class="token punctuation">(</span>vnode<span class="token punctuation">.</span>elm <span class="token operator">=</span> oldVnode<span class="token punctuation">.</span>elm<span class="token punctuation">)</span>
  <span class="token comment">// 如果当前节点是注释或 v-if 的，或者是异步函数，就跳过检查异步组件</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isTrue</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">.</span>isAsyncPlaceholder<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span>vnode<span class="token punctuation">.</span>asyncFactory<span class="token punctuation">.</span>resolved<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">hydrate</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">.</span>elm<span class="token punctuation">,</span> vnode<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">)</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      vnode<span class="token punctuation">.</span>isAsyncPlaceholder <span class="token operator">=</span> <span class="token boolean">true</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 当前节点是静态节点的时候，key 也一样，或者有 v-once 的时候，就直接赋值返回</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>
    <span class="token function">isTrue</span><span class="token punctuation">(</span>vnode<span class="token punctuation">.</span>isStatic<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
    <span class="token function">isTrue</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">.</span>isStatic<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
    vnode<span class="token punctuation">.</span>key <span class="token operator">===</span> oldVnode<span class="token punctuation">.</span>key <span class="token operator">&amp;&amp;</span>
    <span class="token punctuation">(</span><span class="token function">isTrue</span><span class="token punctuation">(</span>vnode<span class="token punctuation">.</span>isCloned<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token function">isTrue</span><span class="token punctuation">(</span>vnode<span class="token punctuation">.</span>isOnce<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span> <span class="token punctuation">{</span>
    vnode<span class="token punctuation">.</span>componentInstance <span class="token operator">=</span> oldVnode<span class="token punctuation">.</span>componentInstance
    <span class="token keyword">return</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">let</span> i
  <span class="token keyword">const</span> data <span class="token operator">=</span> vnode<span class="token punctuation">.</span>data
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">isDef</span><span class="token punctuation">(</span><span class="token punctuation">(</span>i <span class="token operator">=</span> data<span class="token punctuation">.</span>hook<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">isDef</span><span class="token punctuation">(</span><span class="token punctuation">(</span>i <span class="token operator">=</span> i<span class="token punctuation">.</span>prepatch<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">i</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">,</span> vnode<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">const</span> oldCh <span class="token operator">=</span> oldVnode<span class="token punctuation">.</span>children
  <span class="token keyword">const</span> ch <span class="token operator">=</span> vnode<span class="token punctuation">.</span>children
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">isPatchable</span><span class="token punctuation">(</span>vnode<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 遍历调用 update 更新 oldVnode 所有属性，比如 class,style,attrs,domProps,events...</span>
    <span class="token comment">// 这里的 update 钩子函数是 vnode 本身的钩子函数</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> cbs<span class="token punctuation">.</span>update<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> cbs<span class="token punctuation">.</span>update<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">,</span> vnode<span class="token punctuation">)</span>
    <span class="token comment">// 这里的 update 钩子函数是我们传过来的函数</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span><span class="token punctuation">(</span>i <span class="token operator">=</span> data<span class="token punctuation">.</span>hook<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">isDef</span><span class="token punctuation">(</span><span class="token punctuation">(</span>i <span class="token operator">=</span> i<span class="token punctuation">.</span>update<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">i</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">,</span> vnode<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 如果新节点不是文本节点，也就是说有子节点</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isUndef</span><span class="token punctuation">(</span>vnode<span class="token punctuation">.</span>text<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 如果新老节点都有子节点</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span>oldCh<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">isDef</span><span class="token punctuation">(</span>ch<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 如果新老节点的子节点不一样，就执行 updateChildren 函数，对比子节点</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>oldCh <span class="token operator">!==</span> ch<span class="token punctuation">)</span> <span class="token function">updateChildren</span><span class="token punctuation">(</span>elm<span class="token punctuation">,</span> oldCh<span class="token punctuation">,</span> ch<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">,</span> removeOnly<span class="token punctuation">)</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span>ch<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 如果新节点有子节点的话，就是说老节点没有子节点</span>

      <span class="token comment">// 如果老节点是文本节点，就是说没有子节点，就清空</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">.</span>text<span class="token punctuation">)</span><span class="token punctuation">)</span> nodeOps<span class="token punctuation">.</span><span class="token function">setTextContent</span><span class="token punctuation">(</span>elm<span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span>
      <span class="token comment">// 添加新节点</span>
      <span class="token function">addVnodes</span><span class="token punctuation">(</span>elm<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> ch<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> ch<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">)</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span>oldCh<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 如果新节点没有子节点，老节点有子节点，就删除</span>
      <span class="token function">removeVnodes</span><span class="token punctuation">(</span>oldCh<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> oldCh<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">.</span>text<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 如果老节点是文本节点，就清空</span>
      nodeOps<span class="token punctuation">.</span><span class="token function">setTextContent</span><span class="token punctuation">(</span>elm<span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>oldVnode<span class="token punctuation">.</span>text <span class="token operator">!==</span> vnode<span class="token punctuation">.</span>text<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 如果老节点的文本和新节点的文本不同，就更新文本</span>
    nodeOps<span class="token punctuation">.</span><span class="token function">setTextContent</span><span class="token punctuation">(</span>elm<span class="token punctuation">,</span> vnode<span class="token punctuation">.</span>text<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDef</span><span class="token punctuation">(</span><span class="token punctuation">(</span>i <span class="token operator">=</span> data<span class="token punctuation">.</span>hook<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">isDef</span><span class="token punctuation">(</span><span class="token punctuation">(</span>i <span class="token operator">=</span> i<span class="token punctuation">.</span>postpatch<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">i</span><span class="token punctuation">(</span>oldVnode<span class="token punctuation">,</span> vnode<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div></div> <h3 id="diff-双端算法核心-update-patch-patch-patchvnode-updatechildren"><a href="#diff-双端算法核心-update-patch-patch-patchvnode-updatechildren" class="header-anchor">#</a> diff 双端算法核心: <code>_update -&gt; __patch__ -&gt; patch -&gt; patchVnode -&gt; updateChildren</code></h3> <p><a href="/blog/article/js-upgrade/算法/2-1-0、算法导读.html">手撸双端 diff</a></p> <div class="custom-block warning"><p class="custom-block-title">src/core/vdom/patch.js</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">updateChildren</span><span class="token punctuation">(</span><span class="token parameter">parentElm<span class="token punctuation">,</span> oldCh<span class="token punctuation">,</span> newCh<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">,</span> removeOnly</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> oldStartIdx <span class="token operator">=</span> <span class="token number">0</span>
  <span class="token keyword">let</span> newStartIdx <span class="token operator">=</span> <span class="token number">0</span>
  <span class="token keyword">let</span> oldEndIdx <span class="token operator">=</span> oldCh<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span>
  <span class="token keyword">let</span> oldStartVnode <span class="token operator">=</span> oldCh<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span>
  <span class="token keyword">let</span> oldEndVnode <span class="token operator">=</span> oldCh<span class="token punctuation">[</span>oldEndIdx<span class="token punctuation">]</span>
  <span class="token keyword">let</span> newEndIdx <span class="token operator">=</span> newCh<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span>
  <span class="token keyword">let</span> newStartVnode <span class="token operator">=</span> newCh<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span>
  <span class="token keyword">let</span> newEndVnode <span class="token operator">=</span> newCh<span class="token punctuation">[</span>newEndIdx<span class="token punctuation">]</span>
  <span class="token keyword">let</span> oldKeyToIdx<span class="token punctuation">,</span> idxInOld<span class="token punctuation">,</span> vnodeToMove<span class="token punctuation">,</span> refElm

  <span class="token comment">// removeOnly is a special flag used only by &lt;transition-group&gt;</span>
  <span class="token comment">// to ensure removed elements stay in correct relative positions</span>
  <span class="token comment">// during leaving transitions</span>
  <span class="token keyword">const</span> canMove <span class="token operator">=</span> <span class="token operator">!</span>removeOnly

  <span class="token keyword">while</span> <span class="token punctuation">(</span>oldStartIdx <span class="token operator">&lt;=</span> oldEndIdx <span class="token operator">&amp;&amp;</span> newStartIdx <span class="token operator">&lt;=</span> newEndIdx<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isUndef</span><span class="token punctuation">(</span>oldStartVnode<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      oldStartVnode <span class="token operator">=</span> oldCh<span class="token punctuation">[</span><span class="token operator">++</span>oldStartIdx<span class="token punctuation">]</span> <span class="token comment">// Vnode has been moved left</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isUndef</span><span class="token punctuation">(</span>oldEndVnode<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      oldEndVnode <span class="token operator">=</span> oldCh<span class="token punctuation">[</span><span class="token operator">--</span>oldEndIdx<span class="token punctuation">]</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">sameVnode</span><span class="token punctuation">(</span>oldStartVnode<span class="token punctuation">,</span> newStartVnode<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">patchVnode</span><span class="token punctuation">(</span>oldStartVnode<span class="token punctuation">,</span> newStartVnode<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">,</span> newCh<span class="token punctuation">,</span> newStartIdx<span class="token punctuation">)</span>
      oldStartVnode <span class="token operator">=</span> oldCh<span class="token punctuation">[</span><span class="token operator">++</span>oldStartIdx<span class="token punctuation">]</span>
      newStartVnode <span class="token operator">=</span> newCh<span class="token punctuation">[</span><span class="token operator">++</span>newStartIdx<span class="token punctuation">]</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">sameVnode</span><span class="token punctuation">(</span>oldEndVnode<span class="token punctuation">,</span> newEndVnode<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">patchVnode</span><span class="token punctuation">(</span>oldEndVnode<span class="token punctuation">,</span> newEndVnode<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">,</span> newCh<span class="token punctuation">,</span> newEndIdx<span class="token punctuation">)</span>
      oldEndVnode <span class="token operator">=</span> oldCh<span class="token punctuation">[</span><span class="token operator">--</span>oldEndIdx<span class="token punctuation">]</span>
      newEndVnode <span class="token operator">=</span> newCh<span class="token punctuation">[</span><span class="token operator">--</span>newEndIdx<span class="token punctuation">]</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">sameVnode</span><span class="token punctuation">(</span>oldStartVnode<span class="token punctuation">,</span> newEndVnode<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// Vnode moved right</span>
      <span class="token function">patchVnode</span><span class="token punctuation">(</span>oldStartVnode<span class="token punctuation">,</span> newEndVnode<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">,</span> newCh<span class="token punctuation">,</span> newEndIdx<span class="token punctuation">)</span>
      canMove <span class="token operator">&amp;&amp;</span> nodeOps<span class="token punctuation">.</span><span class="token function">insertBefore</span><span class="token punctuation">(</span>parentElm<span class="token punctuation">,</span> oldStartVnode<span class="token punctuation">.</span>elm<span class="token punctuation">,</span> nodeOps<span class="token punctuation">.</span><span class="token function">nextSibling</span><span class="token punctuation">(</span>oldEndVnode<span class="token punctuation">.</span>elm<span class="token punctuation">)</span><span class="token punctuation">)</span>
      oldStartVnode <span class="token operator">=</span> oldCh<span class="token punctuation">[</span><span class="token operator">++</span>oldStartIdx<span class="token punctuation">]</span>
      newEndVnode <span class="token operator">=</span> newCh<span class="token punctuation">[</span><span class="token operator">--</span>newEndIdx<span class="token punctuation">]</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">sameVnode</span><span class="token punctuation">(</span>oldEndVnode<span class="token punctuation">,</span> newStartVnode<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// Vnode moved left</span>
      <span class="token function">patchVnode</span><span class="token punctuation">(</span>oldEndVnode<span class="token punctuation">,</span> newStartVnode<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">,</span> newCh<span class="token punctuation">,</span> newStartIdx<span class="token punctuation">)</span>
      canMove <span class="token operator">&amp;&amp;</span> nodeOps<span class="token punctuation">.</span><span class="token function">insertBefore</span><span class="token punctuation">(</span>parentElm<span class="token punctuation">,</span> oldEndVnode<span class="token punctuation">.</span>elm<span class="token punctuation">,</span> oldStartVnode<span class="token punctuation">.</span>elm<span class="token punctuation">)</span>
      oldEndVnode <span class="token operator">=</span> oldCh<span class="token punctuation">[</span><span class="token operator">--</span>oldEndIdx<span class="token punctuation">]</span>
      newStartVnode <span class="token operator">=</span> newCh<span class="token punctuation">[</span><span class="token operator">++</span>newStartIdx<span class="token punctuation">]</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isUndef</span><span class="token punctuation">(</span>oldKeyToIdx<span class="token punctuation">)</span><span class="token punctuation">)</span> oldKeyToIdx <span class="token operator">=</span> <span class="token function">createKeyToOldIdx</span><span class="token punctuation">(</span>oldCh<span class="token punctuation">,</span> oldStartIdx<span class="token punctuation">,</span> oldEndIdx<span class="token punctuation">)</span>
      idxInOld <span class="token operator">=</span> <span class="token function">isDef</span><span class="token punctuation">(</span>newStartVnode<span class="token punctuation">.</span>key<span class="token punctuation">)</span>
        <span class="token operator">?</span> oldKeyToIdx<span class="token punctuation">[</span>newStartVnode<span class="token punctuation">.</span>key<span class="token punctuation">]</span>
        <span class="token operator">:</span> <span class="token function">findIdxInOld</span><span class="token punctuation">(</span>newStartVnode<span class="token punctuation">,</span> oldCh<span class="token punctuation">,</span> oldStartIdx<span class="token punctuation">,</span> oldEndIdx<span class="token punctuation">)</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isUndef</span><span class="token punctuation">(</span>idxInOld<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// New element</span>
        <span class="token function">createElm</span><span class="token punctuation">(</span>newStartVnode<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">,</span> parentElm<span class="token punctuation">,</span> oldStartVnode<span class="token punctuation">.</span>elm<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">,</span> newCh<span class="token punctuation">,</span> newStartIdx<span class="token punctuation">)</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        vnodeToMove <span class="token operator">=</span> oldCh<span class="token punctuation">[</span>idxInOld<span class="token punctuation">]</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">sameVnode</span><span class="token punctuation">(</span>vnodeToMove<span class="token punctuation">,</span> newStartVnode<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token function">patchVnode</span><span class="token punctuation">(</span>vnodeToMove<span class="token punctuation">,</span> newStartVnode<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">,</span> newCh<span class="token punctuation">,</span> newStartIdx<span class="token punctuation">)</span>
          oldCh<span class="token punctuation">[</span>idxInOld<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">undefined</span>
          canMove <span class="token operator">&amp;&amp;</span> nodeOps<span class="token punctuation">.</span><span class="token function">insertBefore</span><span class="token punctuation">(</span>parentElm<span class="token punctuation">,</span> vnodeToMove<span class="token punctuation">.</span>elm<span class="token punctuation">,</span> oldStartVnode<span class="token punctuation">.</span>elm<span class="token punctuation">)</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          <span class="token comment">// same key but different element. treat as new element</span>
          <span class="token function">createElm</span><span class="token punctuation">(</span>
            newStartVnode<span class="token punctuation">,</span>
            insertedVnodeQueue<span class="token punctuation">,</span>
            parentElm<span class="token punctuation">,</span>
            oldStartVnode<span class="token punctuation">.</span>elm<span class="token punctuation">,</span>
            <span class="token boolean">false</span><span class="token punctuation">,</span>
            newCh<span class="token punctuation">,</span>
            newStartIdx
          <span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
      newStartVnode <span class="token operator">=</span> newCh<span class="token punctuation">[</span><span class="token operator">++</span>newStartIdx<span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>oldStartIdx <span class="token operator">&gt;</span> oldEndIdx<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    refElm <span class="token operator">=</span> <span class="token function">isUndef</span><span class="token punctuation">(</span>newCh<span class="token punctuation">[</span>newEndIdx <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token keyword">null</span> <span class="token operator">:</span> newCh<span class="token punctuation">[</span>newEndIdx <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>elm
    <span class="token function">addVnodes</span><span class="token punctuation">(</span>parentElm<span class="token punctuation">,</span> refElm<span class="token punctuation">,</span> newCh<span class="token punctuation">,</span> newStartIdx<span class="token punctuation">,</span> newEndIdx<span class="token punctuation">,</span> insertedVnodeQueue<span class="token punctuation">)</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>newStartIdx <span class="token operator">&gt;</span> newEndIdx<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">removeVnodes</span><span class="token punctuation">(</span>oldCh<span class="token punctuation">,</span> oldStartIdx<span class="token punctuation">,</span> oldEndIdx<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">更新时间:</span> <span class="time">2023年9月4日星期一上午10点30分</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/blog/article/框架/vue/手撸ViewModel.html" class="prev">
        手撸ViewModel
      </a></span> <span class="next"><a href="/blog/article/前端工程化/CI&amp;CD/CI&amp;CD.html">
        持续集成与交付
      </a>
      →
    </span></p></div> </main></div><div class="global-ui"></div></div>
    <script src="/blog/assets/js/app.7b4540b9.js" defer></script><script src="/blog/assets/js/2.b0da3abb.js" defer></script><script src="/blog/assets/js/90.9963ca39.js" defer></script>
  </body>
</html>
